<!doctype html>
<!--suppress HtmlUnknownTarget, HtmlRequiredAltAttribute, XmlDeprecatedElement, CheckImageSize -->
<html lang="en">

<head>
    <title>The Illustrated TLS 1.3 Connection: Every Byte Explained</title>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
    <meta name="format-detection" content="telephone=no"/>
    <meta name="title" content="The Illustrated TLS 1.3 Connection"/>
    <meta name="description" content="Every byte of a TLS 1.3 connection explained and reproduced"/>
    <link rel="stylesheet" href="frombootstrap.css?b1"/>
    <link rel="stylesheet" href="illustrated.css?b1"/>
    <script src="illustrated.js?b1"></script>

    <!-- Facebook Meta Tags -->
    <meta property="og:url" content="https://tls13.xargs.org/">
    <meta property="og:type" content="website">
    <meta property="og:title" content="The Illustrated TLS 1.3 Connection">
    <meta property="og:description" content="Every byte of a TLS connection explained and reproduced">
    <meta property="og:image" content="https://tls13.xargs.org/images/og.png">

    <!-- Twitter Meta Tags -->
    <meta name="twitter:card" content="summary_large_image">
    <meta property="twitter:domain" content="tls13.xargs.org">
    <meta property="twitter:url" content="https://tls13.xargs.org/">
    <meta name="twitter:title" content="The Illustrated TLS 1.3 Connection">
    <meta name="twitter:description" content="Every byte of a TLS connection explained and reproduced">
    <meta name="twitter:image" content="https://tls13.xargs.org/images/og.png#b">

    <!-- favicons -->
    <link rel="apple-touch-icon" sizes="152x152" href="favicon/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="favicon/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="favicon/favicon-16x16.png">
    <link rel="manifest" href="favicon/site.webmanifest">
    <link rel="mask-icon" href="favicon/safari-pinned-tab.svg" color="#5bbad5">
    <link rel="shortcut icon" href="favicon.ico">
    <meta name="msapplication-TileColor" content="#da532c">
    <meta name="msapplication-config" content="favicon/browserconfig.xml">
    <meta name="theme-color" content="#ffffff">
</head>

<body class="illustrated">
<div class="header">
    <a href="https://quic.xargs.org">QUIC</a>
    <a href="https://dtls.xargs.org">DTLS</a>
    <a class="this-page" href="https://tls13.xargs.org">TLS 1.3</a>
    <a href="https://tls12.xargs.org">TLS 1.2</a>
</div>
<h1>The Illustrated TLS 1.3 Connection</h1>
<div class="container">

    <h3>Every byte explained and reproduced</h3>

    <div class="outerblock">
    <p>In this demonstration a client connects to a server,
    negotiates a TLS 1.3 session, sends "ping", receives "pong",
    and then terminates the session. Click below to begin
    exploring.</p>
    </div>

<div class="open-close-all rec-outer">
    <button id="openCloseAll" class="annotate-toggle"
        data-lbl-state="open" data-lbl-toggle="Close All"
        onclick="ill.openCloseAll(this, event)">Open All</button>
</div>

<div class="rec-outer">
<div class="calculation client">
<div class="rec-label">Client Key Exchange Generation</div>
<img class="illustration" src="images/key6.png" width="105" height="250"/>
<div class="rec-explanation">
    <p>The client begins by generating a private/public keypair
    for key exchange.  Key exchange is a technique
    where two parties can agree on the same number without
    an eavesdropper being able to tell what the number is.
    <p>
    An explanation of the key exchange can be found on my
    <a href="https://x25519.xargs.org/">X25519 site</a>,
    but doesn't need to be understood in depth for the rest
    of this page.
    <p>
    The private key is chosen by selecting an integer between
    0 and 2<sup>256</sup>-1.  The client does this by generating 32
    bytes (256 bits) of random data.  The
    <a href="files/client-ephemeral-private.key" download="client-ephemeral-private.key">private key</a>
    selected is:

    <pre class="ind2"><tt class="longboi"
    >202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f</tt></pre>

    The <a href="files/client-ephemeral-public.key" download="client-ephemeral-public.key">public key</a>
    is created from the private key as explained on the <a href="https://x25519.xargs.org/">X25519 site</a>.
    The public key calculated is:

    <pre class="ind2"><tt class="longboi"
    >358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254</tt></pre>

    The public key calculation can be confirmed at the command line:
    <codesample>
<pre><code>### requires openssl 1.1.0 or higher
$ openssl pkey -noout -text &lt; client-ephemeral-private.key

X25519 Private-Key:
priv:
    20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:
    2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:
    3e:3f
pub:
    35:80:72:d6:36:58:80:d1:ae:ea:32:9a:df:91:21:
    38:38:51:ed:21:a2:8e:3b:75:e9:65:d0:d2:cd:16:
    62:54
</code></pre>
    </codesample>
</div>
</div>
</div>

<div class="rec-outer">
<div class="record client">
<div class="rec-label">Client Hello</div>
<img class="illustration" src="images/key1.png" width="135" height="250"/>
<div class="rec-explanation">
    The session begins with the client saying "Hello".
    The client provides information including the following:
    <ul>
    <li>client random data (used later in the handshake)
    <li>a list of cipher suites that the client supports
    <li>a list of public keys that the server might find suitable for key exchange
    <li>protocol versions that the client can support
    </ul>
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 16 03 01 00 f8
        </span>
        <div class="explanation">
            TLS sessions are broken into the sending
            and receiving of "records", which are blocks
            of data with a type, a protocol version,
            and a length.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake record)
            <li><tt>03 01</tt> - protocol version is "3,1" (also known as TLS 1.0)
            <li><tt>00 f8</tt> - 0xF8 (248) bytes of handshake message follows
            </ul>
            Interestingly the version in this record
            is "3,1" (TLS 1.0) instead of "3,4" (TLS 1.3).
            This is done for interoperability with earlier
            implementations.
        </div>
    </span>

    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 01 00 00 f4
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>01</tt> - handshake message type 0x01 (client hello)
            <li><tt>00 00 f4</tt> - 0xF4 (244) bytes of client hello data follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Client Version</span>
        <span class="bytes">
 03 03
        </span>
        <div class="explanation">
            A protocol version of "3,3" (meaning TLS 1.2)
            is given.  Because middleboxes have been
            created and widely deployed that do not
            allow protocol versions that
            they do not recognize, the TLS 1.3 session
            must be disguised as a TLS 1.2 session.
            This field is no
            longer used for version negotiation and
            is hardcoded to the 1.2 version.  Instead,
            version negotiation is performed using the
            "Supported Versions" extension below.
            <br/><br/>
            The unusual version number ("3,3" representing
            TLS 1.2) is due to TLS 1.0 being a minor
            revision of the SSL 3.0 protocol.  Therefore
            TLS 1.0 is represented by "3,1", TLS 1.1 is
            "3,2", and so on.
        </div>
    </span>

    <span class="string">
        <span class="label">Client Random</span>
        <span class="bytes">
 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
        </span>
        <div class="explanation">
            The client provides 32 bytes of random data.  This data will be used later in the session.
            In this example we've made the random data a predictable string.
        </div>
    </span>

    <span class="string">
        <span class="label">Session ID</span>
        <span class="bytes">
 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe
 ff
        </span>
        <div class="explanation">
            In previous versions of TLS the client could
            provide an ID of a previously negotiated
            session, which allows the server and client
            to skip the time and cost of negotiating new keys.
            <br/><br/>
            In TLS 1.3 this "session resume" is done via the more flexible
            PSK (pre-shared keys) mechanism, so this
            field is no longer needed for that purpose.
            Instead, a non-empty value in this field is
            used to trigger "middlebox compatibility
            mode" which helps TLS 1.3 sessions to be
            disguised as resumed TLS 1.2 sessions.  The
            client has generated random data to populate
            this field.
            <ul>
            <li><tt>20</tt> - 0x20 (32) bytes of session ID follow
            <li><tt>e0 e1 ... fe ff</tt> - fake session ID
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Cipher Suites</span>
        <span class="bytes">
 00 08 13 02 13 03 13 01 00 ff
        </span>
        <div class="explanation">
            The client provides an ordered list of which
            cipher suites it will support for encryption.
            The list is in the order preferred by the
            client, with highest preference first.
            <br/><br/>
            In TLS 1.3 the list of possible cipher
            suites has been greatly reduced.  All the
            remaining suites are AEAD algorithms which
            provide stronger encryption guarantees than
            many previous suites with an easier all-in-one
            implementation.
            <ul>
            <li><tt>00 08</tt> - 8 bytes of cipher suite data
            <li><tt>13 02</tt> - assigned value for <tt>TLS_AES_256_GCM_SHA384</tt>
            <li><tt>13 03</tt> - assigned value for <tt>TLS_CHACHA20_POLY1305_SHA256</tt>
            <li><tt>13 01</tt> - assigned value for <tt>TLS_AES_128_GCM_SHA256</tt>
            <li><tt>00 ff</tt> - assigned value for <tt>TLS_EMPTY_RENEGOTIATION_INFO_SCSV</tt>
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Compression Methods</span>
        <span class="bytes">
 01 00
        </span>
        <div class="explanation">
            Previous versions of TLS supported
            compression, which was found to leak
            information about the encrypted data allowing
            it to be read (see <a href="https://en.wikipedia.org/wiki/CRIME">CRIME</a>).
            <br/><br/>
            TLS 1.3 no longer allows compression, so
            this field is always a single entry with
            the "null" compression method which performs
            no change to the data.
            <ul>
            <li><tt>01</tt> - 1 bytes of compression methods
            <li><tt>00</tt> - assigned value for "null" compression
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extensions Length</span>
        <span class="bytes">
 00 a3
        </span>
        <div class="explanation">
            The client has provided a list of optional
            extensions which the server can use to
            take action or enable new features.
            <ul>
            <li><tt>00 a3</tt> - the extensions will take 0xA3 (163) bytes of data
            </ul>
            Each extension will start with two bytes
            that indicate which extension it is, followed
            by a two-byte content length field, followed
            by the contents of the extension.
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Server Name</span>
        <span class="bytes">
 00 00 00 18 00 16 00 00 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74
        </span>
        <div class="explanation">
            The client has provided the name of the
            server it is contacting, also known as SNI
            (Server Name Indication).
            <br/><br/>
            Without this extension an HTTPS server would
            not be able to provide service for multiple
            hostnames (virtual hosts) on a single IP address
            because it couldn't know which
            hostname's certificate to send until
            after the TLS session was negotiated and the
            HTTP request was made.
            <ul>
                <li><tt>00 00</tt> - assigned value for extension "server name"
                <li><tt>00 18</tt> - 0x18 (24) bytes of "server name" extension data follows
                <li><tt>00 16</tt> - 0x16 (22) bytes of first (and only) list entry follows
                <li><tt>00</tt> - list entry is type 0x00 "DNS hostname"
                <li><tt>00 13</tt> - 0x13 (19) bytes of hostname follows
                <li><tt>65 78 61 ... 6e 65 74</tt> - "example.ulfheim.net"
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - EC Point Formats</span>
        <span class="bytes">
 00 0b 00 04 03 00 01 02
        </span>
        <div class="explanation">
            The client has indicated that it supports receiving
            elliptic curve data points in the following compression formats:
            <ul>
                <li><tt>00 0b</tt> - assigned value for extension "ec point formats"
                <li><tt>00 04</tt> - 4 bytes of format types follow
                <li><tt>03</tt> - 3 bytes of format types follow
                <li><tt>00</tt> - assigned value for format "uncompressed"
                <li><tt>01</tt> - assigned value for format "ansiX962_compressed_prime"
                <li><tt>02</tt> - assigned value for format "ansiX962_compressed_char2"
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Supported Groups</span>
        <span class="bytes">
 00 0a 00 16 00 14 00 1d 00 17 00 1e 00 19 00 18 01 00 01 01 01 02 01 03 01 04
        </span>
        <div class="explanation">
            The client has indicated that it supports
            elliptic curve (EC) cryptography for ten curve types.
            To make this extension more generic for
            other cryptography types it calls these
            "supported groups" instead of "supported
            curves".
            <br/><br/>
            This list is presented in descending order
            of the client's preference.
            <ul>
                <li><tt>00 0a</tt> - assigned value for extension "supported groups"
                <li><tt>00 16</tt> - 0x16 (22) bytes of "supported group" extension data follows
                <li><tt>00 14</tt> - 0x14 (20) bytes of data are in the curves list
                <li><tt>00 1d</tt> - assigned value for the curve "x25519"
                <li><tt>00 17</tt> - assigned value for the curve "secp256r1"
                <li><tt>00 1e</tt> - assigned value for the curve "x448"
                <li><tt>00 19</tt> - assigned value for the curve "secp521r1"
                <li><tt>00 18</tt> - assigned value for the curve "secp384r1"
                <li><tt>01 00</tt> - assigned value for the curve "ffdhe2048"
                <li><tt>01 01</tt> - assigned value for the curve "ffdhe3072"
                <li><tt>01 02</tt> - assigned value for the curve "ffdhe4096"
                <li><tt>01 03</tt> - assigned value for the curve "ffdhe6144"
                <li><tt>01 04</tt> - assigned value for the curve "ffdhe8192"
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Session Ticket</span>
        <span class="bytes">
 00 23 00 00
        </span>
        <div class="explanation">
            The client indicates it has no session ticket
            to provide for this connection.
            <ul>
            <li><tt>00 23</tt> - assigned value for extension "Session Ticket"
            <li><tt>00 00</tt> - 0 bytes of "Session Ticket" extension data follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Encrypt-Then-MAC</span>
        <span class="bytes">
 00 16 00 00
        </span>
        <div class="explanation">
            The client indicates it can support EtM, which prevents
            <a href="https://iacr.org/archive/crypto2001/21390309.pdf"
            >certain vulnerabilities</a> in earlier versions of TLS.  In
            TLS 1.3 this mechanism is always used, so this extension
            will have no effect in this session.
            <ul>
                <li><tt>00 16</tt> - assigned value for extension "Encrypt Then MAC"
                <li><tt>00 00</tt> - 0 bytes of "Encrypt Then MAC" extension data follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Extended Master Secret</span>
        <span class="bytes">
 00 17 00 00
        </span>
        <div class="explanation">
            The client indicates support for extra cryptographic operations
            which prevent vulnerabilities in earlier versions of TLS (see <a
            href="https://www.ietf.org/rfc/rfc7627.html">RFC 7627</a> for details).
            In TLS 1.3 the vulnerabilities are no longer present, so this extension
            will have no effect in this session.
            <ul>
                <li><tt>00 17</tt> - assigned value for extension "Extended Master Secret"
                <li><tt>00 00</tt> - 0 bytes of "Extended Master Secret" extension data follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Signature Algorithms</span>
        <span class="bytes">
 00 0d 00 1e 00 1c 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01
 06 01
        </span>
        <div class="explanation">
            This extension indicates which signature
            algorithms the client supports.  This can
            influence the certificate that the server
            presents to the client, as well as the
            signature that is sent by the server in
            the CertificateVerify record.
            <br/><br/>
            This list is presented in descending order
            of the client's preference.
            <ul>
                <li><tt>00 0d</tt> - assigned value for extension "Signature Algorithms"
                <li><tt>00 1e</tt> - 0x1E (30) bytes of "Signature Algorithms" extension data follows
                <li><tt>00 1c</tt> - 0x1C (28) bytes of data are in the following list of algorithms
                <li><tt>04 03</tt> - assigned value for ECDSA-SECP256r1-SHA256
                <li><tt>05 03</tt> - assigned value for ECDSA-SECP384r1-SHA384
                <li><tt>06 03</tt> - assigned value for ECDSA-SECP521r1-SHA512
                <li><tt>08 07</tt> - assigned value for ED25519
                <li><tt>08 08</tt> - assigned value for ED448
                <li><tt>08 09</tt> - assigned value for RSA-PSS-PSS-SHA256
                <li><tt>08 0a</tt> - assigned value for RSA-PSS-PSS-SHA384
                <li><tt>08 0b</tt> - assigned value for RSA-PSS-PSS-SHA512
                <li><tt>08 04</tt> - assigned value for RSA-PSS-RSAE-SHA256
                <li><tt>08 05</tt> - assigned value for RSA-PSS-RSAE-SHA384
                <li><tt>08 06</tt> - assigned value for RSA-PSS-RSAE-SHA512
                <li><tt>04 01</tt> - assigned value for RSA-PKCS1-SHA256
                <li><tt>05 01</tt> - assigned value for RSA-PKCS1-SHA384
                <li><tt>06 01</tt> - assigned value for RSA-PKCS1-SHA512
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Supported Versions</span>
        <span class="bytes">
 00 2b 00 03 02 03 04
        </span>
        <div class="explanation">
            The client indicates its support of TLS 1.3. This is the only indication in the
            Client Hello record that hints the client supports TLS 1.3, since
            for compatibility reasons it has otherwise pretended to be a TLS 1.2 connection
            attempt.
            <ul>
                <li><tt>00 2b</tt> - assigned value for extension "Supported Versions"
                <li><tt>00 03</tt> - 3 bytes of "Supported Versions" extension data follows
                <li><tt>02</tt> - 2 bytes of TLS versions follow
                <li><tt>03 04</tt> - assigned value for TLS 1.3
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - PSK Key Exchange Modes</span>
        <span class="bytes">
 00 2d 00 02 01 01
        </span>
        <div class="explanation">
            The client indicates the modes available
            for establishing keys from pre-shared keys
            (PSKs).  Since we do not use PSKs in this
            session, this extension has no effect.
            <ul>
                <li><tt>00 2d</tt> - assigned value for extension "PSK Key Exchange Modes"
                <li><tt>00 02</tt> - 2 bytes of "PSK Key Exchange Modes" extension data follows
                <li><tt>01</tt> - 1 bytes of exchange modes follow
                <li><tt>01</tt> - assigned value for "PSK with (EC)DHE key establishment"
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Key Share</span>
        <span class="bytes">
 00 33 00 26 00 24 00 1d 00 20 35 80 72 d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed 21 a2 8e
 3b 75 e9 65 d0 d2 cd 16 62 54
        </span>
        <div class="explanation">
            The client sends one or more ephemeral public keys
            using algorithm(s) that it thinks the server
            will support.  This allows the
            rest of the handshake after the ClientHello
            and ServerHello messages to be encrypted,
            unlike previous protocol versions where the
            handshake was sent in the clear.
            <ul>
                <li><tt>00 33</tt> - assigned value for extension "Key Share"
                <li><tt>00 26</tt> - 0x26 (38) bytes of "Key Share" extension data follows
                <li><tt>00 24</tt> - 0x24 (36) bytes of key share data follows
                <li><tt>00 1d</tt> - assigned value for x25519 (key exchange via curve25519)
                <li><tt>00 20</tt> - 0x20 (32) bytes of public key follows
                <li><tt>35 80 ... 62 54</tt> - public key from the step "Client Key Exchange Generation"
            </ul>
        </div>
    </span>

</span>
</div>
</div>

<div class="rec-outer">
<div class="calculation server">
<div class="rec-label">Server Key Exchange Generation</div>
<img class="illustration" src="images/key4.png" width="106" height="250"/>
<div class="rec-explanation">
    <p>The server generates a private/public keypair
    for key exchange.  Key exchange is a technique
    where two parties can agree on the same number without
    an eavesdropper being able to tell what it is.
    <p>
    An explanation of the key exchange can be found on my
    <a href="https://x25519.xargs.org/">X25519 site</a>,
    but doesn't need to be understood in depth for the rest
    of this page.
    <p>
    The private key is chosen by selecting an integer between
    0 and 2<sup>256</sup>-1.  The server does this by generating 32
    bytes (256 bits) of random data.  The
    <a href="files/server-ephemeral-private.key" download="server-ephemeral-private.key">private key</a>
    selected is:

    <pre class="ind2"><tt class="longboi"
    >909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf</tt></pre>

    The <a href="files/server-ephemeral-public.key" download="server-ephemeral-public.key">public key</a>
    is created from the private key as explained on the <a href="https://x25519.xargs.org/">X25519 site</a>.
    The public key calculated is:

    <pre class="ind2"><tt class="longboi"
    >9fd7ad6dcff4298dd3f96d5b1b2af910a0535b1488d7f8fabb349a982880b615</tt></pre>

    The public key calculation can be confirmed at the command line:
    <codesample>
<pre><code>### requires openssl 1.1.0 or higher
$ openssl pkey -noout -text &lt; server-ephemeral-private.key

X25519 Private-Key:
priv:
    90:91:92:93:94:95:96:97:98:99:9a:9b:9c:9d:9e:
    9f:a0:a1:a2:a3:a4:a5:a6:a7:a8:a9:aa:ab:ac:ad:
    ae:af
pub:
    9f:d7:ad:6d:cf:f4:29:8d:d3:f9:6d:5b:1b:2a:f9:
    10:a0:53:5b:14:88:d7:f8:fa:bb:34:9a:98:28:80:
    b6:15
</code></pre>
    </codesample>
</div>
</div>
</div>

<div class="rec-outer">
<div class="record server">
<div class="rec-label">Server Hello</div>
<img class="illustration" src="images/key2.png" width="124" height="250"/>
<div class="rec-explanation">
    The server says "Hello" back.  The server provides information including the following:
    <ul>
    <li>server random data (used later in the handshake)
    <li>a selected cipher suite
    <li>a public key for key exchange
    <li>the negotiated protocol version
    </ul>
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 16 03 03 00 7a
        </span>
        <div class="explanation">
            TLS sessions are broken into the sending
            and receiving of "records", which are blocks
            of data with a type, a protocol version,
            and a length.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake record)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 7a</tt> - 0x7A (122) bytes of handshake message follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 02 00 00 76
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>02</tt> - handshake message type 0x02 (server hello)
            <li><tt>00 00 76</tt> - 0x76 (118) bytes of server hello data follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Server Version</span>
        <span class="bytes">
 03 03
        </span>
        <div class="explanation">
            A protocol version of "3,3" (meaning TLS 1.2)
            is given.  Because middleboxes have been
            created and widely deployed that do not
            allow protocol versions that
            they do not recognize, the TLS 1.3 session
            must be disguised as a TLS 1.2 session.
            This field is no
            longer used for version negotiation and
            is hardcoded to the 1.2 version.  Instead,
            version negotiation is performed using the
            "Supported Versions" extension below.
            <br/><br/>
            The unusual version number ("3,3" representing
            TLS 1.2) is due to TLS 1.0 being a minor
            revision of the SSL 3.0 protocol.  Therefore
            TLS 1.0 is represented by "3,1", TLS 1.1 is
            "3,2", and so on.
        </div>
    </span>

    <span class="string">
        <span class="label">Server Random</span>
        <span class="bytes">
 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f
        </span>
        <div class="explanation">
            The server provides 32 bytes of random data.  This data will be used later in the session.
            In this example we've made the random data a predictable string.
        </div>
    </span>

    <span class="string">
        <span class="label">Session ID</span>
        <span class="bytes">
 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe
 ff
        </span>
        <div class="explanation">
            This legacy field is no longer used to
            identify and re-use sessions.  Instead, the
            server echos the session ID provided by the
            client, if any.
            <ul>
            <li><tt>20</tt> - 0x20 (32) bytes of session ID follow
            <li><tt>e0 e1 ... fe ff</tt> - session ID copied from Client Hello
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Cipher Suite</span>
        <span class="bytes">
 13 02
        </span>
        <div class="explanation">
            The server has selected cipher suite 0x1302
            (TLS_AES_256_GCM_SHA384) from the list of options given by the client.
        </div>
    </span>

    <span class="string">
        <span class="label">Compression Method</span>
        <span class="bytes">
 00
        </span>
        <div class="explanation">
            The server has selected compression method
            0x00 ("Null", which performs no compression)
            from the list of options given by the client.
        </div>
    </span>

    <span class="string">
        <span class="label">Extensions Length</span>
        <span class="bytes">
 00 2e
        </span>
        <div class="explanation">
            The server has returned a list of extensions
            to the client.  Because the server is
            forbidden from replying with an extension
            that the client did not send in its hello
            message, the server knows that the client
            will understand and support all extensions listed.
            <ul>
            <li><tt>00 2e</tt> - the extensions will take 0x2E (46) bytes of data
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Supported Versions</span>
        <span class="bytes">
 00 2b 00 02 03 04
        </span>
        <div class="explanation">
            The server indicates the negotiated TLS version of 1.3.
            <ul>
                <li><tt>00 2b</tt> - assigned value for extension "Supported Versions"
                <li><tt>00 02</tt> - 2 bytes of "Supported Versions" extension data follows
                <li><tt>03 04</tt> - assigned value for TLS 1.3
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extension - Key Share</span>
        <span class="bytes">
 00 33 00 24 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa
 bb 34 9a 98 28 80 b6 15
        </span>
        <div class="explanation">
            The server sends a public key using the algorithm
            of the public key sent by the client.  Once this is sent
            encryption keys can be calculated and the rest of the
            handshake will be encrypted,
            unlike previous protocol versions where the
            handshake was sent in the clear.
            <ul>
                <li><tt>00 33</tt> - assigned value for extension "Key Share"
                <li><tt>00 24</tt> - 0x24 (36) bytes of "Key Share" extension data follows
                <li><tt>00 1d</tt> - assigned value for x25519 (key exchange via curve25519)
                <li><tt>00 20</tt> - 0x20 (32) bytes of public key follows
                <li><tt>9f d7 ... b6 15</tt> - public key from the step "Server Key Exchange Generation"
            </ul>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="calculation server">
<div class="rec-label">Server Handshake Keys Calc</div>
<img class="illustration" src="images/key9.png" width="97" height="250"/>
<div class="rec-explanation">
    The server now has the information to calculate the
    keys used to encrypt the rest of the handshake.  It uses the following
    information in this calculation:
    <ul>
    <li><a href="files/client-ephemeral-public.key">client public key</a> (from Client Hello)
    <li><a href="files/server-ephemeral-private.key">server private key</a> (from Server Key Exchange Generation)
    <li>SHA384 hash of ClientHello and ServerHello</li>
    </ul>
    First, the server finds the shared secret, which is the
    result of the key exchange that allows the client and server
    to agree on a number.  The server multiplies the client's
    public key by the server's private key using the curve25519()
    algorithm.  The 32-byte result is found to be:
    <pre class="ind2"><tt class="longboi"
    >df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624</tt></pre>

    I've provided <a href="files/curve25519-mult.c" download="curve25519-mult.c">a tool</a>
    to perform this calculation:
    <codesample>
<pre><code>$ cc -o curve25519-mult curve25519-mult.c
$ ./curve25519-mult server-ephemeral-private.key \
                    client-ephemeral-public.key | hexdump

0000000 df 4a 29 1b aa 1e b7 cf a6 93 4b 29 b4 74 ba ad
0000010 26 97 e2 9f 1f 92 0d cc 77 c8 a0 a0 88 44 76 24
</code></pre>
    </codesample>

    We then calculate the SHA384 hash of all handshake messages
    to this point (ClientHello and ServerHello).  The hash does
    not include the 5-byte "record" headers.  This "hello_hash"
    is <tt class="longboi"
    >e05f64fcd082bdb0dce473adf669c2769f257a1c75a51b7887468b5e0e7a7de4f4d34555112077f16e079019d5a845bd</tt>:
    <codesample>
<pre><code>$ (tail -c +6 clienthello; tail -c +6 serverhello) | openssl sha384
e05f64fcd082bdb0dce473adf669c2769f257a1c75a51b7887468b5e0e7a7de4f4d34555112077f16e079019d5a845bd
</code></pre>
    </codesample>

    We then feed the hash and the shared secret into a set of
    key derivation operations, designed to ensure the integrity
    of the handshake process and to protect against known and
    possible attacks:

    <processblock>
<pre>early_secret = HKDF-Extract(salt: 00, key: 00...)
empty_hash = SHA384("")
derived_secret = HKDF-Expand-Label(key: early_secret, label: "derived", ctx: empty_hash, len: 48)
handshake_secret = HKDF-Extract(salt: derived_secret, key: shared_secret)
client_secret = HKDF-Expand-Label(key: handshake_secret, label: "c hs traffic", ctx: hello_hash, len: 48)
server_secret = HKDF-Expand-Label(key: handshake_secret, label: "s hs traffic", ctx: hello_hash, len: 48)
client_handshake_key = HKDF-Expand-Label(key: client_secret, label: "key", ctx: "", len: 32)
server_handshake_key = HKDF-Expand-Label(key: server_secret, label: "key", ctx: "", len: 32)
client_handshake_iv = HKDF-Expand-Label(key: client_secret, label: "iv", ctx: "", len: 12)
server_handshake_iv = HKDF-Expand-Label(key: server_secret, label: "iv", ctx: "", len: 12)
</pre>
    </processblock>

    This has introduced two new cryptographic methods:
    <ul>
    <li><tt>HKDF-Extract</tt> - given a salt and some bytes of key material
    create 384 bits (48 bytes) of new key material, with the
    input key material's entropy evenly distributed in the
    output.
    <li><tt>HKDF-Expand-Label</tt> - given the inputs of key
    material, label, and context data, create a new key of the
    requested length.
    </ul>

    I've created <a href="files/hkdf-384.sh" download="hkdf-384">an HKDF tool</a>
    to perform these operations on the command line.
    <codesample>
<pre><code>$ hello_hash=e05f64fcd082bdb0dce473adf669c2769f257a1c75a51b7887468b5e0e7a7de4f4d34555112077f16e079019d5a845bd
$ shared_secret=df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624
$ zero_key=000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
$ early_secret=$(./hkdf-384 extract 00 $zero_key)
$ empty_hash=$(openssl sha384 < /dev/null | sed -e 's/.* //')
$ derived_secret=$(./hkdf-384 expandlabel $early_secret "derived" $empty_hash 48)
$ handshake_secret=$(./hkdf-384 extract $derived_secret $shared_secret)
$ csecret=$(./hkdf-384 expandlabel $handshake_secret "c hs traffic" $hello_hash 48)
$ ssecret=$(./hkdf-384 expandlabel $handshake_secret "s hs traffic" $hello_hash 48)
$ client_handshake_key=$(./hkdf-384 expandlabel $csecret "key" "" 32)
$ server_handshake_key=$(./hkdf-384 expandlabel $ssecret "key" "" 32)
$ client_handshake_iv=$(./hkdf-384 expandlabel $csecret "iv" "" 12)
$ server_handshake_iv=$(./hkdf-384 expandlabel $ssecret "iv" "" 12)
$ echo hssec: $handshake_secret
$ echo ssec: $ssecret
$ echo csec: $csecret
$ echo skey: $server_handshake_key
$ echo siv: $server_handshake_iv
$ echo ckey: $client_handshake_key
$ echo civ: $client_handshake_iv

hssec: bdbbe8757494bef20de932598294ea65b5e6bf6dc5c02a960a2de2eaa9b07c929078d2caa0936231c38d1725f179d299
ssec: 23323da031634b241dd37d61032b62a4f450584d1f7f47983ba2f7cc0cdcc39a68f481f2b019f9403a3051908a5d1622
csec: db89d2d6df0e84fed74a2288f8fd4d0959f790ff23946cdf4c26d85e51bebd42ae184501972f8d30c4a3e4a3693d0ef0
skey: 9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
siv: 9563bc8b590f671f488d2da3
ckey: 1135b4826a9a70257e5a391ad93093dfd7c4214812f493b3e3daae1eb2b1ac69
civ: 4256d2e0e88babdd05eb2f27
</code></pre>
    </codesample>

    From this we get the following key data:
    <ul>
    <li>handshake secret: <tt class="longboi"
    >bdbbe8757494bef20de932598294ea65b5e6bf6dc5c02a960a2de2eaa9b07c929078d2caa0936231c38d1725f179d299</tt>
    <li>server handshake traffic secret: <tt class="longboi"
    >23323da031634b241dd37d61032b62a4f450584d1f7f47983ba2f7cc0cdcc39a68f481f2b019f9403a3051908a5d1622</tt>.
    <li>client handshake traffic secret: <tt class="longboi"
    >db89d2d6df0e84fed74a2288f8fd4d0959f790ff23946cdf4c26d85e51bebd42ae184501972f8d30c4a3e4a3693d0ef0</tt>.
    <li>server handshake key: <tt class="longboi"
    >9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f</tt>
    <li>server handshake IV: <tt class="longboi"
    >9563bc8b590f671f488d2da3</tt>
    <li>client handshake key: <tt class="longboi"
    >1135b4826a9a70257e5a391ad93093dfd7c4214812f493b3e3daae1eb2b1ac69</tt>
    <li>client handshake IV: <tt class="longboi"
    >4256d2e0e88babdd05eb2f27</tt>
    </ul>
</div>
</div>
</div>

<div class="rec-outer">
<div class="calculation client">
<div class="rec-label">Client Handshake Keys Calc</div>
<img class="illustration" src="images/key8.png" width="97" height="250"/>
<div class="rec-explanation">
    The client now has the information to calculate the
    keys used to encrypt the rest of the handshake.  It uses the following
    information in this calculation:
    <ul>
    <li><a href="files/server-ephemeral-public.key">server public key</a> (from Server Hello)
    <li><a href="files/client-ephemeral-private.key">client private key</a> (from Client Key Exchange Generation)
    <li>SHA384 hash of ClientHello and ServerHello</li>
    </ul>
    First, the client finds the shared secret, which is the
    result of the key exchange that allows the client and server
    to agree on a number.  The client multiplies the server's
    public key by the client's private key using the curve25519()
    algorithm. The properties of elliptic curve multiplication will
    cause this to result in the same number found by the server in its
    multiplication. The 32-byte result is found to be:
    <pre class="ind2"><tt class="longboi"
    >df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624</tt></pre>

    I've provided <a href="files/curve25519-mult.c" download="curve25519-mult.c">a tool</a>
    to perform this calculation:
    <codesample>
<pre><code>$ cc -o curve25519-mult curve25519-mult.c
$ ./curve25519-mult client-ephemeral-private.key \
                    server-ephemeral-public.key | hexdump

0000000 df 4a 29 1b aa 1e b7 cf a6 93 4b 29 b4 74 ba ad
0000010 26 97 e2 9f 1f 92 0d cc 77 c8 a0 a0 88 44 76 24
</code></pre>
    </codesample>
    Since the shared secret above is the same number calculated by the
    server in "Server Handshake Keys Calc", the rest of
    the calculation is identical and the same values are found:
    <ul>
    <li>server handshake key: <tt class="longboi"
    >9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f</tt>
    <li>server handshake IV: <tt class="longboi"
    >9563bc8b590f671f488d2da3</tt>
    <li>client handshake key: <tt class="longboi"
    >1135b4826a9a70257e5a391ad93093dfd7c4214812f493b3e3daae1eb2b1ac69</tt>
    <li>client handshake IV: <tt class="longboi"
    >4256d2e0e88babdd05eb2f27</tt>
    </ul>
</div>
</div>
</div>

<div class="rec-outer">
<div class="record server">
<div class="rec-label">Server Change Cipher Spec</div>
<div class="rec-explanation">
    This record served a purpose in earlier versions on TLS but is no longer needed.
    In "middlebox compatibility mode" this record is sent to help disguise the session as
    a TLS 1.2 session.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 14 03 03 00 01 01
        </span>
        <div class="explanation">
            TLS sessions are broken into the sending
            and receiving of "records", which are blocks
            of data with a type, a protocol version,
            and a length.
            <ul>
            <li><tt>14</tt> - type is 0x14 (ChangeCipherSpec record)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 01</tt> - the length of the record payload is 1 bytes
            <li><tt>01</tt> - the payload of this message is defined as the byte 0x01
            </ul>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="record server">
<div class="rec-label">Wrapped Record</div>
<img class="illustration" src="images/key5.png" width="124" height="250"/>
<div class="rec-explanation">
    The connection (including the handshake) is encrypted from
    this point on.  The encryption of handshake data is new in
    TLS 1.3.
    <br/><br/>
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, the encrypted handshake records are disguised as a
    TLS 1.2 session that has performed a successful session
    resume.
    <br/><br/>
    This wrapped record is discussed in its own section below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 00 17
        </span>
        <div class="explanation">
            The TLS 1.3 records are encrypted into a
            TLS 1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 17</tt> - 0x17 (23) bytes of wrapped data follows
            </ul>
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 6b e0 2f 9d a7 c2 dc
        </span>
        <div class="explanation">
            This data is encrypted with the server handshake key.
        </div>
    </span>
    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 9d de f5 6f 24 68 b9 0a df a2 51 01 ab 03 44 ae
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the server
            handshake key and the server handshake IV that were
            generated during the "Server Handshake Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 0.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Server Handshake Keys Calc" step
$ key=9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
$ iv=9563bc8b590f671f488d2da3
### from this record
$ recdata=1703030017
$ authtag=9ddef56f2468b90adfa25101ab0344ae
$ recordnum=0
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "6b e0 2f 9d a7 c2 dc" | xxd -r -p > /tmp/msg1
$ cat /tmp/msg1 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  08 00 00 02 00 00 16                              |.......|
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Encrypted Extensions</span>
        <span class="bytes">
 08 00 00 02 00 00
        </span>
        <div class="explanation">
            This handshake message is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 16
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final byte
            which indicates its actual record type.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake record)
            </ul>
        </div>
    </span>

</span>
</div>
</div>

<div class="rec-outer">
<div class="record server embedded">
<div class="rec-label">Server Encrypted Extensions</div>
<div class="rec-explanation">
    Any extensions that aren't needed for negotiating encryption
    keys should be listed here so that they can be hidden from
    eavesdroppers and middleboxes.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 08 00 00 02
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>08</tt> - handshake message type 0x08 (encrypted extensions)
            <li><tt>00 00 02</tt> - 2 bytes of handshake message data follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Extensions</span>
        <span class="bytes">
 00 00
        </span>
        <div class="explanation">
            <ul>
            <li><tt>00 00</tt> - 0 bytes of extension data follows
            </ul>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="record server">
<div class="rec-label">Wrapped Record</div>
<img class="illustration" src="images/key5.png" width="124" height="250"/>
<div class="rec-explanation">
    The encryption of handshake data is new in TLS 1.3.
    <br/><br/>
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, the encrypted handshake records are disguised as a
    TLS 1.2 session that has performed a successful session
    resume.
    <br/><br/>
    This wrapped record is discussed in its own section below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 03 43
        </span>
        <div class="explanation">
            The TLS 1.3 records are encrypted into a
            TLS 1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>03 43</tt> - 0x343 (835) bytes of wrapped data follows
            </ul>
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 ba f0 0a 9b e5 0f 3f 23 07 e7 26 ed cb da cb e4 b1 86 16 44 9d 46 c6 20 7a f6 e9 95 3e e5 d2 41
 1b a6 5d 31 fe af 4f 78 76 4f 2d 69 39 87 18 6c c0 13 29 c1 87 a5 e4 60 8e 8d 27 b3 18 e9 8d d9
 47 69 f7 73 9c e6 76 83 92 ca ca 8d cc 59 7d 77 ec 0d 12 72 23 37 85 f6 e6 9d 6f 43 ef fa 8e 79
 05 ed fd c4 03 7e ee 59 33 e9 90 a7 97 2f 20 69 13 a3 1e 8d 04 93 13 66 d3 d8 bc d6 a4 a4 d6 47
 dd 4b d8 0b 0f f8 63 ce 35 54 83 3d 74 4c f0 e0 b9 c0 7c ae 72 6d d2 3f 99 53 df 1f 1c e3 ac eb
 3b 72 30 87 1e 92 31 0c fb 2b 09 84 86 f4 35 38 f8 e8 2d 84 04 e5 c6 c2 5f 66 a6 2e be 3c 5f 26
 23 26 40 e2 0a 76 91 75 ef 83 48 3c d8 1e 6c b1 6e 78 df ad 4c 1b 71 4b 04 b4 5f 6a c8 d1 06 5a
 d1 8c 13 45 1c 90 55 c4 7d a3 00 f9 35 36 ea 56 f5 31 98 6d 64 92 77 53 93 c4 cc b0 95 46 70 92
 a0 ec 0b 43 ed 7a 06 87 cb 47 0c e3 50 91 7b 0a c3 0c 6e 5c 24 72 5a 78 c4 5f 9f 5f 29 b6 62 68
 67 f6 f7 9c e0 54 27 35 47 b3 6d f0 30 bd 24 af 10 d6 32 db a5 4f c4 e8 90 bd 05 86 92 8c 02 06
 ca 2e 28 e4 4e 22 7a 2d 50 63 19 59 35 df 38 da 89 36 09 2e ef 01 e8 4c ad 2e 49 d6 2e 47 0a 6c
 77 45 f6 25 ec 39 e4 fc 23 32 9c 79 d1 17 28 76 80 7c 36 d7 36 ba 42 bb 69 b0 04 ff 55 f9 38 50
 dc 33 c1 f9 8a bb 92 85 83 24 c7 6f f1 eb 08 5d b3 c1 fc 50 f7 4e c0 44 42 e6 22 97 3e a7 07 43
 41 87 94 c3 88 14 0b b4 92 d6 29 4a 05 40 e5 a5 9c fa e6 0b a0 f1 48 99 fc a7 13 33 31 5e a0 83
 a6 8e 1d 7c 1e 4c dc 2f 56 bc d6 11 96 81 a4 ad bc 1b bf 42 af d8 06 c3 cb d4 2a 07 6f 54 5d ee
 4e 11 8d 0b 39 67 54 be 2b 04 2a 68 5d d4 72 7e 89 c0 38 6a 94 d3 cd 6e cb 98 20 e9 d4 9a fe ed
 66 c4 7e 6f c2 43 ea be bb cb 0b 02 45 38 77 f5 ac 5d bf bd f8 db 10 52 a3 c9 94 b2 24 cd 9a aa
 f5 6b 02 6b b9 ef a2 e0 13 02 b3 64 01 ab 64 94 e7 01 8d 6e 5b 57 3b d3 8b ce f0 23 b1 fc 92 94
 6b bc a0 20 9c a5 fa 92 6b 49 70 b1 00 91 03 64 5c b1 fc fe 55 23 11 ff 73 05 58 98 43 70 03 8f
 d2 cc e2 a9 1f c7 4d 6f 3e 3e a9 f8 43 ee d3 56 f6 f8 2d 35 d0 3b c2 4b 81 b5 8c eb 1a 43 ec 94
 37 e6 f1 e5 0e b6 f5 55 e3 21 fd 67 c8 33 2e b1 b8 32 aa 8d 79 5a 27 d4 79 c6 e2 7d 5a 61 03 46
 83 89 19 03 f6 64 21 d0 94 e1 b0 0a 9a 13 8d 86 1e 6f 78 a2 0a d3 e1 58 00 54 d2 e3 05 25 3c 71
 3a 02 fe 1e 28 de ee 73 36 24 6f 6a e3 43 31 80 6b 46 b4 7b 83 3c 39 b9 d3 1c d3 00 c2 a6 ed 83
 13 99 77 6d 07 f5 70 ea f0 05 9a 2c 68 a5 f3 ae 16 b6 17 40 4a f7 b7 23 1a 4d 94 27 58 fc 02 0b
 3f 23 ee 8c 15 e3 60 44 cf d6 7c d6 40 99 3b 16 20 75 97 fb f3 85 ea 7a 4d 99 e8 d4 56 ff 83 d4
 1f 7b 8b 4f 06 9b 02 8a 2a 63 a9 19 a7 0e 3a 10 e3 08 41
        </span>
        <div class="explanation">
            This data is encrypted with the server handshake key.
        </div>
    </span>
    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 58 fa a5 ba fa 30 18 6c 6b 2f 23 8e b5 30 c7 3e
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the server
            handshake key and the server handshake IV that were
            generated during the "Server Handshake Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 1.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Server Handshake Keys Calc" step
$ key=9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
$ iv=9563bc8b590f671f488d2da3
### from this record
$ recdata=1703030343
$ authtag=58faa5bafa30186c6b2f238eb530c73e
$ recordnum=1
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "ba f0 0a 9b e5 0f 3f 23 07 e7 26 ed cb da cb e4 b1 86 16
  ... snip ...
  a9 19 a7 0e 3a 10 e3 08 41" | xxd -r -p > /tmp/msg1
$ cat /tmp/msg1 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  08 00 00 02 00 00 0b 00  03 2e 00 00 03 2a 00 03  |.............*..|
00000010  25 30 82 03 21 30 82 02  09 a0 03 02 01 02 02 08  |58..!0..........|
00000020  15 5a 92 ad c2 04 8f 90  30 0d 06 09 2a 86 48 86  |.Z......0...*.H.|
00000000  0b 00 03 2e 00 00 03 2a  00 03 25 30 82 03 21 30  |.......*..58..!0|
00000010  82 02 09 a0 03 02 01 02  02 08 15 5a 92 ad c2 04  |...........Z....|
00000020  8f 90 30 0d 06 09 2a 86  48 86 f7 0d 01 01 0b 05  |..0...*.H.......|
00000030  00 30 22 31 0b 30 09 06  03 55 04 06 13 02 55 53  |.0"1.0...U....US|
00000040  31 13 30 11 06 03 55 04  0a 13 0a 45 78 61 6d 70  |1.0...U....Examp|
... snip ...
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Server Certificate</span>
        <span class="bytes">
 0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04
 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53
 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30
 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06
 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e
 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82
 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7 b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00
 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d
 f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1 f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b
 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7 f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69
 ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5 ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16
 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40
 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10 d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad
 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1
 ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03
 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55
 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52 cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09
 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b
 fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd
 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24 f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65
 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9
 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4 ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e
 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42 c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27
 cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f
 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4
 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0 00 00
        </span>
        <div class="explanation">
            This handshake message is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 16
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final byte
            which indicates its actual record type.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake record)
            </ul>
        </div>
    </span>

</span>
</div>
</div>

<div class="rec-outer">
<div class="record server embedded">
<div class="rec-label">Server Certificate</div>
<img class="illustration" src="images/key3.png" width="130" height="250"/>
<div class="rec-explanation">
    The server sends one or more certificates:
    <ul>
    <li>the certificate for this host, containing the hostname,
    a public key, and a signature from a third party asserting
    that the owner of the certificate's hostname holds the
    private key for this certificate
    <li>an optional list of further certificates, each of which signs
    the previous certificate, and which form a chain of trust
    leading from the host certificate to a trusted certificate
    that has been pre-installed on the client
    </ul>
    In an effort to keep this example small we only send a
    host certificate.  Certificates are in a binary format
    called DER <a href="certificate.html" target="_blank">which
    you can explore here</a>.

</div>
<span class="record-data">
    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 0b 00 03 2e
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>0b</tt> - handshake message type 0x0B (certificate)
            <li><tt>00 03 2e</tt> - 0x32E (814) bytes of certificate payload follow
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Request Context</span>
        <span class="bytes">
 00
        </span>
        <div class="explanation">
            This record is empty because this certificate was not sent in
            response to a Certificate Request.
            <ul>
            <li><tt>00</tt> - 0 bytes of request context follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Certificates Length</span>
        <span class="bytes">
 00 03 2a
        </span>
        <div class="explanation">
            <ul>
            <li><tt>00 03 2a</tt> - 0x32A (810) bytes of certificates follow
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Certificate Length</span>
        <span class="bytes">
 00 03 25
        </span>
        <div class="explanation">
            The length of the first (and only) certificate.
            <ul>
            <li><tt>00 03 25</tt> - 0x325 (805) bytes of certificate follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Certificate</span>
        <span class="bytes">
 30 82 03 21 30 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04 8f 90 30 0d 06 09 2a 86 48 86 f7
 0d 01 01 0b 05 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 13 30 11 06 03 55 04 0a 13 0a
 45 78 61 6d 70 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30 31 33 38 31 37 5a 17 0d 31 39 31
 30 30 35 30 31 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 1c 30 1a 06 03 55
 04 03 13 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 30 82 01 22 30 0d 06 09 2a
 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01 00 c4 80 36 06 ba e7 47 6b
 08 94 04 ec a7 b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc
 73 e7 02 4c 0d bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d f3 e1 09 59 54 7b c9 55 fb 41 2d
 a3 76 52 11 e1 f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b 31 d5 6c b6 52 9c 80 98 bc c9 e0
 28 18 e2 0b f7 f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69 ec 47 97 2e 83 0f b5 ca 95 de 95
 a1 e6 04 22 d5 ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16 95 1a 4c f7 a0 46 92 59 5c 13 52
 f2 54 9e 5a fb 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40 7d 7d 23 07 44 01 f4 84 ff d0 8f
 7a 1f a0 52 10 d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad 6b 4b b7 11 01 f4 4b ad 66 6a 11
 13 0f e2 ee 82 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1 ba 94 21 02 03 01 00 01 a3 52 30
 50 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06
 01 05 05 07 03 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55 1d 23 04 18 30 16 80 14 89 4f de
 5b cc 69 e2 52 cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00
 03 82 01 01 00 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b fd 6c d7 55 99 b5 e7 c3 6e 53 3e
 ff 36 59 08 43 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd 09 c1 cf 1d 91 44 55 87 0b 57 1d
 d1 9b df 1d 24 f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65 1e 61 8c e5 98 fa 96 e5 37 2e ef
 3d 24 8a fd e1 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9 2f 78 19 66 0d 3f 27 cf 20 9e 66
 7f ce 5a e2 e4 ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e 3e 93 49 d4 c6 6c 9e a6 39 6d 74
 44 62 a0 6b 42 c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27 cb 69 d3 cc dc a2 80 41 44 65 d3
 ae 34 8c e0 f3 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f 11 a5 d6 5c 84 4f 04 04 84 99 38
 71 2b 95 9e d6 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4 0e 34 69 a1 59 41 e8 e2 cc a8 4b
 b6 08 46 36 a0
        </span>
        <div class="explanation">
            The certificate is in ASN.1 DER
            encoding.  The details of this format and
            the content of this binary payload are
            documented <a href="certificate.html" target="_blank">on another page</a>.
            <a href="files/server.crt" download="server.crt">The certificate</a>
            can be converted to the binary data in this message
            at the command line:
            <codesample>
<pre><code>$ openssl x509 -outform der &lt; server.crt | hexdump

0000000 30 82 03 21 30 82 02 09 a0 03 02 01 02 02 08 15
0000010 5a 92 ad c2 04 8f 90 30 0d 06 09 2a 86 48 86 f7
... snip ...
</code></pre>
            </codesample>
        </div>
    </span>

    <span class="string">
        <span class="label">Certificate Extensions</span>
        <span class="bytes">
 00 00
        </span>
        <div class="explanation">
            The server can provide extension data for the certificate.
            <ul>
            <li><tt>00 00</tt> - 0 bytes of extension data follows
            </ul>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="record server">
<div class="rec-label">Wrapped Record</div>
<img class="illustration" src="images/key5.png" width="124" height="250"/>
<div class="rec-explanation">
    The encryption of handshake data is new in TLS 1.3.
    <br/><br/>
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, the encrypted handshake records are disguised as a
    TLS 1.2 session that has performed a successful session
    resume.
    <br/><br/>
    This wrapped record is discussed in its own section below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 01 19
        </span>
        <div class="explanation">
            The TLS 1.3 records are encrypted into a
            TLS 1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>01 19</tt> - 0x119 (281) bytes of wrapped data follows
            </ul>
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 73 71 9f ce 07 ec 2f 6d 3b ba 02 92 a0 d4 0b 27 70 c0 6a 27 17 99 a5 33 14 f6 f7 7f c9 5c 5f e7
 b9 a4 32 9f d9 54 8c 67 0e be ea 2f 2d 5c 35 1d d9 35 6e f2 dc d5 2e b1 37 bd 3a 67 65 22 f8 cd
 0f b7 56 07 89 ad 7b 0e 3c ab a2 e3 7e 6b 41 99 c6 79 3b 33 46 ed 46 cf 74 0a 9f a1 fe c4 14 dc
 71 5c 41 5c 60 e5 75 70 3c e6 a3 4b 70 b5 19 1a a6 a6 1a 18 fa ff 21 6c 68 7a d8 d1 7e 12 a7 e9
 99 15 a6 11 bf c1 a2 be fc 15 e6 e9 4d 78 46 42 e6 82 fd 17 38 2a 34 8c 30 10 56 b9 40 c9 84 72
 00 40 8b ec 56 c8 1e a3 d7 21 7a b8 e8 5a 88 71 53 95 89 9c 90 58 7f 72 e8 dd d7 4b 26 d8 ed c1
 c7 c8 37 d9 f2 eb bc 26 09 62 21 90 38 b0 56 54 a6 3a 0b 12 99 9b 4a 83 06 a3 dd cc 0e 17 c5 3b
 a8 f9 c8 03 63 f7 84 13 54 d2 91 b4 ac e0 c0 f3 30 c0 fc d5 aa 9d ee f9 69 ae 8a b2 d9 8d a8 8e
 bb 6e a8 0a 3a 11 f0 0e a2
        </span>
        <div class="explanation">
            This data is encrypted with the server handshake key.
        </div>
    </span>
    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 96 a3 23 23 67 ff 07 5e 1c 66 dd 9c be dc 47 13
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the server
            handshake key and the server handshake IV that were
            generated during the "Server Handshake Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 2.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Server Handshake Keys Calc" step
$ key=9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
$ iv=9563bc8b590f671f488d2da3
### from this record
$ recdata=1703030119
$ authtag=96a3232367ff075e1c66dd9cbedc4713
$ recordnum=2
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "73 71 9f ce 07 ec 2f 6d 3b ba 02 92 a0 d4 0b 27 70 c0 6a 27
  ... snip ...
  d9 8d a8 8e bb 6e a8 0a 3a 11 f0 0e a2" | xxd -r -p > /tmp/msg1
$ cat /tmp/msg1 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  0f 00 01 04 08 04 01 00  5c bb 24 c0 40 93 32 da  |........\.$.@.2.|
00000010  a9 20 bb ab bd b9 bd 50  17 0b e4 9c fb e0 a4 10  |. .....P........|
00000020  7f ca 6f fb 10 68 e6 5f  96 9e 6d e7 d4 f9 e5 60  |..o..h._..m....`|
... snip ...
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Server Certificate Verify</span>
        <span class="bytes">
 0f 00 01 04 08 04 01 00 5c bb 24 c0 40 93 32 da a9 20 bb ab bd b9 bd 50 17 0b e4 9c fb e0 a4 10
 7f ca 6f fb 10 68 e6 5f 96 9e 6d e7 d4 f9 e5 60 38 d6 7c 69 c0 31 40 3a 7a 7c 0b cc 86 83 e6 57
 21 a0 c7 2c c6 63 40 19 ad 1d 3a d2 65 a8 12 61 5b a3 63 80 37 20 84 f5 da ec 7e 63 d3 f4 93 3f
 27 22 74 19 a6 11 03 46 44 dc db c7 be 3e 74 ff ac 47 3f aa ad de 8c 2f c6 5f 32 65 77 3e 7e 62
 de 33 86 1f a7 05 d1 9c 50 6e 89 6c 8d 82 f5 bc f3 5f ec e2 59 b7 15 38 11 5e 9c 8c fb a6 2e 49
 bb 84 74 f5 85 87 b1 1b 8a e3 17 c6 33 e9 c7 6c 79 1d 46 62 84 ad 9c 4f f7 35 a6 d2 e9 63 b5 9b
 bc a4 40 a3 07 09 1a 1b 4e 46 bc c7 a2 f9 fb 2f 1c 89 8e cb 19 91 8b e4 12 1d 7e 8e d0 4c d5 0c
 9a 59 e9 87 98 01 07 bb bf 29 9c 23 2e 7f db e1 0a 4c fd ae 5c 89 1c 96 af df f9 4b 54 cc d2 bc
 19 d3 cd aa 66 44 85 9c
        </span>
        <div class="explanation">
            This handshake message is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 16
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final byte
            which indicates its actual record type.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake record)
            </ul>
        </div>
    </span>

</span>
</div>
</div>

<div class="rec-outer">
<div class="record server embedded">
<div class="rec-label">Server Certificate Verify</div>
<div class="rec-explanation">
    The server provides information that ties the public key
    generated during Server Key Exchange Generation to the
    ownership of the certificate's private key.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 0f 00 01 04
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>0f</tt> - handshake message type 0x0f (certificate verify)
            <li><tt>00 01 04</tt> - 0x104 (260) bytes of handshake message data follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Signature</span>
        <span class="bytes">
 08 04 01 00 5c bb 24 c0 40 93 32 da a9 20 bb ab bd b9 bd 50 17 0b e4 9c fb e0 a4 10 7f ca 6f fb
 10 68 e6 5f 96 9e 6d e7 d4 f9 e5 60 38 d6 7c 69 c0 31 40 3a 7a 7c 0b cc 86 83 e6 57 21 a0 c7 2c
 c6 63 40 19 ad 1d 3a d2 65 a8 12 61 5b a3 63 80 37 20 84 f5 da ec 7e 63 d3 f4 93 3f 27 22 74 19
 a6 11 03 46 44 dc db c7 be 3e 74 ff ac 47 3f aa ad de 8c 2f c6 5f 32 65 77 3e 7e 62 de 33 86 1f
 a7 05 d1 9c 50 6e 89 6c 8d 82 f5 bc f3 5f ec e2 59 b7 15 38 11 5e 9c 8c fb a6 2e 49 bb 84 74 f5
 85 87 b1 1b 8a e3 17 c6 33 e9 c7 6c 79 1d 46 62 84 ad 9c 4f f7 35 a6 d2 e9 63 b5 9b bc a4 40 a3
 07 09 1a 1b 4e 46 bc c7 a2 f9 fb 2f 1c 89 8e cb 19 91 8b e4 12 1d 7e 8e d0 4c d5 0c 9a 59 e9 87
 98 01 07 bb bf 29 9c 23 2e 7f db e1 0a 4c fd ae 5c 89 1c 96 af df f9 4b 54 cc d2 bc 19 d3 cd aa
 66 44 85 9c
        </span>
        <div class="explanation">
            Because the server is generating ephemeral
            keys for each session (optional in TLS 1.2,
            mandatory in TLS 1.3) the session is not
            inherently tied to the certificate as it
            was in previous versions of TLS, when the
            certificate's public/private key were used
            for key exchange.
            <br/><br/>
            To prove
            that the server owns the server certificate
            (giving the certificate validity in this
            TLS session), it signs a hash of the handshake
            messages using the private key associated with the certificate.
            The signature can be proven valid by
            the client by using the public key included in the certificate.
            <ul>
            <li><tt>08 04</tt> - reserved value for RSA-PSS-RSAE-SHA256 signature
            <li><tt>01 00</tt> - 0x100 (256) bytes of signature data follows
            <li><tt>5c bb 24 ... 44 85 9c</tt> - a signature over this handshake's hash
            </ul>
            The signing process can't be reproduced byte-for-byte
            at the command line because the signing tool introduces
            random or changing data into the signature.
            <br/><br/>
            We can verify the signature using the
            <a href="files/server.crt" download="server.crt">server's certificate</a>
            at the command line:
            <codesample>
<pre><code>### find the hash of the conversation to this point, excluding
### 5-byte record headers or 1-byte wrapped record trailers
$ handshake_hash=$((
   tail -c +6 clienthello;
   tail -c +6 serverhello;
   perl -pe 's/.$// if eof' serverextensions;
   perl -pe 's/.$// if eof' servercert) | openssl sha384)

### build the data that was signed:
### 1. add 64 space characters
$ echo -n '                                ' > /tmp/tosign
$ echo -n '                                ' >> /tmp/tosign
### 2. add this fixed string
$ echo -n 'TLS 1.3, server CertificateVerify' >> /tmp/tosign
### 3. add a single null character
$ echo -en '\0' >> /tmp/tosign
### 4. add hash of handshake to this point
$ echo $handshake_hash | xxd -r -p >> /tmp/tosign

### copy the signature that we want to verify
$ echo "5c bb 24 c0 40 93 32 da a9 20 bb ab bd b9 bd 50 17 0b e4 9c
  fb e0 a4 10 7f ca 6f fb 10 68 e6 5f 96 9e 6d e7 d4 f9 e5 60 38 d6
  7c 69 c0 31 40 3a 7a 7c 0b cc 86 83 e6 57 21 a0 c7 2c c6 63 40 19
  ad 1d 3a d2 65 a8 12 61 5b a3 63 80 37 20 84 f5 da ec 7e 63 d3 f4
  93 3f 27 22 74 19 a6 11 03 46 44 dc db c7 be 3e 74 ff ac 47 3f aa
  ad de 8c 2f c6 5f 32 65 77 3e 7e 62 de 33 86 1f a7 05 d1 9c 50 6e
  89 6c 8d 82 f5 bc f3 5f ec e2 59 b7 15 38 11 5e 9c 8c fb a6 2e 49
  bb 84 74 f5 85 87 b1 1b 8a e3 17 c6 33 e9 c7 6c 79 1d 46 62 84 ad
  9c 4f f7 35 a6 d2 e9 63 b5 9b bc a4 40 a3 07 09 1a 1b 4e 46 bc c7
  a2 f9 fb 2f 1c 89 8e cb 19 91 8b e4 12 1d 7e 8e d0 4c d5 0c 9a 59
  e9 87 98 01 07 bb bf 29 9c 23 2e 7f db e1 0a 4c fd ae 5c 89 1c 96
  af df f9 4b 54 cc d2 bc 19 d3 cd aa 66 44 85 9c" | xxd -r -p > /tmp/sig

### extract the public key from the certificate
$ openssl x509 -pubkey -noout -in server.crt > server.pub

### verify the signature
$ cat /tmp/tosign | openssl dgst -verify server.pub -sha256 \
    -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature /tmp/sig

Verified OK
</code></pre>
            </codesample>
        </div>
    </span>
</span>
</div>
</div>


<div class="rec-outer">
<div class="record server">
<div class="rec-label">Wrapped Record</div>
<img class="illustration" src="images/key5.png" width="124" height="250"/>
<div class="rec-explanation">
    The encryption of handshake data is new in TLS 1.3.
    <br/><br/>
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, the encrypted handshake records are disguised as a
    TLS 1.2 session that has performed a successful session
    resume.
    <br/><br/>
    This wrapped record is discussed in its own section below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 00 45
        </span>
        <div class="explanation">
            The TLS 1.3 records are encrypted into a
            TLS 1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 45</tt> - 0x45 (69) bytes of wrapped data follows
            </ul>
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 10 61 de 27 e5 1c 2c 9f 34 29 11 80 6f 28 2b 71 0c 10 63 2c a5 00 67 55 88 0d bf 70 06 00 2d 0e
 84 fe d9 ad f2 7a 43 b5 19 23 03 e4 df 5c 28 5d 58 e3 c7 62 24
        </span>
        <div class="explanation">
            This data is encrypted with the server handshake key.
        </div>
    </span>
    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 07 84 40 c0 74 23 74 74 4a ec f2 8c f3 18 2f d0
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the server
            handshake key and the server handshake IV that were
            generated during the "Server Handshake Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 3.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Server Handshake Keys Calc" step
$ key=9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
$ iv=9563bc8b590f671f488d2da3
### from this record
$ recdata=1703030045
$ authtag=078440c0742374744aecf28cf3182fd0
$ recordnum=3
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "10 61 de 27 e5 1c 2c 9f 34 29 11 80 6f 28 2b 71 0c 10 63 2c a5 00 67 55 88 0d bf 70 06 00 2d 0e 84 fe d9 ad f2 7a 43 b5 19
  23 03 e4 df 5c 28 5d 58 e3 c7 62 24" | xxd -r -p > /tmp/msg1
$ cat /tmp/msg1 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  14 00 00 30 7e 30 ee cc  b6 b2 3b e6 c6 ca 36 39  |...0~0....;...69|
00000010  92 e8 42 da 87 7e e6 47  15 ae 7f c0 cf 87 f9 e5  |..B..~.G........|
00000020  03 21 82 b5 bb 48 d1 e3  3f 99 79 05 5a 16 0c 8d  |.!...H..?.y.Z...|
00000030  bb b1 56 9c 16                                    |..V..|
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Server Finished</span>
        <span class="bytes">
 14 00 00 30 7e 30 ee cc b6 b2 3b e6 c6 ca 36 39 92 e8 42 da 87 7e e6 47 15 ae 7f c0 cf 87 f9 e5
 03 21 82 b5 bb 48 d1 e3 3f 99 79 05 5a 16 0c 8d bb b1 56 9c
        </span>
        <div class="explanation">
            This handshake message is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 16
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final byte
            which indicates its actual record type.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake record)
            </ul>
        </div>
    </span>
</span>
</div>
</div>


<div class="rec-outer">
<div class="record server embedded">
<div class="rec-label">Server Handshake Finished</div>
<div class="rec-explanation">
    To verify that the handshake was successful and not tampered
    with, the server calculates verification data that client will agree on.
    The verification data is built from a hash of all handshake
    messages.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 14 00 00 30
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>14</tt> - handshake message type 0x14 (finished)
            <li><tt>00 00 30</tt> - 0x30 (48) bytes of handshake finished data follows
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Verify Data</span>
        <span class="bytes">
 7e 30 ee cc b6 b2 3b e6 c6 ca 36 39 92 e8 42 da 87 7e e6 47 15 ae 7f c0 cf 87 f9 e5 03 21 82 b5
 bb 48 d1 e3 3f 99 79 05 5a 16 0c 8d bb b1 56 9c
        </span>
        <div class="explanation">
            The verify_data is built using the
            server_secret from
            the "Server Handshake Keys Calc" step and
            a SHA384 hash of every handshake record
            before this point (Client Hello to Server Certificate
            Verify).

            <processblock class="notrunc">
<pre>finished_key = HKDF-Expand-Label(key: server_secret, label: "finished", ctx: "", len: 48)
finished_hash = SHA384(Client Hello ... Server Cert Verify)
verify_data = HMAC-SHA384(key: finished_key, msg: finished_hash)
</pre>
            </processblock>

            We can use <a href="files/hkdf-384.sh" download="hkdf-384">the HKDF
            tool</a> to reproduce this on the command line.
            <codesample>
<pre><code>### find the hash of the conversation to this point, excluding
### 5-byte record headers or 1-byte wrapped record trailers
$ fin_hash=$((
    tail -c +6 clienthello;
    tail -c +6 serverhello;
    perl -pe 's/.$// if eof' serverextensions;
    perl -pe 's/.$// if eof' servercert;
    perl -pe 's/.$// if eof' servercertverify) | openssl sha384)
$ sht_secret=23323da031634b241dd37d61032b62a4f450584d1f7f47983ba2f7cc0cdcc39a68f481f2b019f9403a3051908a5d1622
$ fin_key=$(./hkdf-384 expandlabel $sht_secret "finished" "" 48)
$ echo $fin_hash | xxd -r -p \
    | openssl dgst -sha384 -mac HMAC -macopt hexkey:$fin_key

7e30eeccb6b23be6c6ca363992e842da877ee64715ae7fc0cf87f9e5032182b5bb48d1e33f9979055a160c8dbbb1569c
</code></pre>
            </codesample>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="calculation server">
<div class="rec-label">Server Application Keys Calc</div>
<img class="illustration" src="images/key9.png" width="97" height="250"/>
<div class="rec-explanation">
    The server now has the information to calculate the
    keys used to encrypt application traffic.
    It uses the following information in this calculation:
    <ul>
    <li>The handshake secret (from "Server Handshake Key Calc")
    <li>The SHA384 hash of every handshake message from Client Hello to Server Handshake Finished</li>
    </ul>
    We calculate the SHA384 hash of all handshake messages to
    this point(Client Hello, Server Hello, [unwrapped] Encrypted Extensions,
    [unwrapped] Server Certificate, [unwrapped] Server Certificate Verify,
    [unwrapped] Server Finished).  The hash input does not include the 5-byte
    "record" headers of ClientHello and ServerHello.  It also
    doesn't include the trailing 1-byte "record type" of unwrapped records.

    This "handshake_hash" is <tt class="longboi"
    >fa6800169a6baac19159524fa7b9721b41be3c9db6f3f93fa5ff7e3db3ece204d2b456c51046e40ec5312c55a86126f5</tt>:
    <codesample>
    <pre><code># strip first 5 bytes of hello records, and trailing byte of unwrapped records
$ (tail -c +6 clienthello; tail -c +6 serverhello; \
   perl -pe 's/.$// if eof' serverextensions; \
   perl -pe 's/.$// if eof' servercert; \
   perl -pe 's/.$// if eof' servercertverify; \
   perl -pe 's/.$// if eof' serverfinished) | openssl sha384

fa6800169a6baac19159524fa7b9721b41be3c9db6f3f93fa5ff7e3db3ece204d2b456c51046e40ec5312c55a86126f5
    </code></pre>
    </codesample>

    We then feed the hash and the handshake secret into a set of
    key derivation operations, designed to ensure the integrity
    of the handshake process and to protect against known and
    possible attacks:

    <processblock>
<pre>empty_hash = SHA384("")
derived_secret = HKDF-Expand-Label(key: handshake_secret, label: "derived", ctx: empty_hash, len: 48)
master_secret = HKDF-Extract(salt: derived_secret, key: 00...)
client_secret = HKDF-Expand-Label(key: master_secret, label: "c ap traffic", ctx: handshake_hash, len: 48)
server_secret = HKDF-Expand-Label(key: master_secret, label: "s ap traffic", ctx: handshake_hash, len: 48)
client_application_key = HKDF-Expand-Label(key: client_secret, label: "key", ctx: "", len: 32)
server_application_key = HKDF-Expand-Label(key: server_secret, label: "key", ctx: "", len: 32)
client_application_iv = HKDF-Expand-Label(key: client_secret, label: "iv", ctx: "", len: 12)
server_application_iv = HKDF-Expand-Label(key: server_secret, label: "iv", ctx: "", len: 12)
</pre>
    </processblock>

    I've created <a href="files/hkdf-384.sh" download="hkdf-384">an HKDF tool</a>
    to perform these operations on the command line.
    <codesample>
<pre><code>$ handshake_hash=fa6800169a6baac19159524fa7b9721b41be3c9db6f3f93fa5ff7e3db3ece204d2b456c51046e40ec5312c55a86126f5
$ handshake_secret=bdbbe8757494bef20de932598294ea65b5e6bf6dc5c02a960a2de2eaa9b07c929078d2caa0936231c38d1725f179d299
$ zero_key=000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
$ empty_hash=$(openssl sha384 < /dev/null | sed -e 's/.* //')
$ derived_secret=$(./hkdf-384 expandlabel $handshake_secret "derived" $empty_hash 48)
$ master_secret=$(./hkdf-384 extract $derived_secret $zero_key)
$ csecret=$(./hkdf-384 expandlabel $master_secret "c ap traffic" $handshake_hash 48)
$ ssecret=$(./hkdf-384 expandlabel $master_secret "s ap traffic" $handshake_hash 48)
$ client_application_key=$(./hkdf-384 expandlabel $csecret "key" "" 32)
$ server_application_key=$(./hkdf-384 expandlabel $ssecret "key" "" 32)
$ client_application_iv=$(./hkdf-384 expandlabel $csecret "iv" "" 12)
$ server_application_iv=$(./hkdf-384 expandlabel $ssecret "iv" "" 12)
$ echo skey: $server_application_key
$ echo siv: $server_application_iv
$ echo ckey: $client_application_key
$ echo civ: $client_application_iv

skey: 01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
siv: 196a750b0c5049c0cc51a541
ckey: de2f4c7672723a692319873e5c227606691a32d1c59d8b9f51dbb9352e9ca9cc
civ: bb007956f474b25de902432f
</code></pre>
    </codesample>

    From this we get the following key data:
    <ul>
    <li>server application key: <tt class="longboi"
    >01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27</tt>
    <li>server application IV: <tt class="longboi">196a750b0c5049c0cc51a541</tt>
    <li>client application key: <tt class="longboi"
    >de2f4c7672723a692319873e5c227606691a32d1c59d8b9f51dbb9352e9ca9cc</tt>
    <li>client application IV: <tt class="longboi">bb007956f474b25de902432f</tt>
    </ul>
</div>
</div>

<div class="rec-outer">
<div class="calculation client">
<div class="rec-label">Client Application Keys Calc</div>
<div class="rec-explanation">
    The client now has the information to calculate the
    keys used to encrypt application traffic.
    It performs the same calculation shown in "Server Application
    Keys Calc" and finds the same values:
    <ul>
    <li>server application key: <tt class="longboi"
    >01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27</tt>
    <li>server application IV: <tt class="longboi">196a750b0c5049c0cc51a541</tt>
    <li>client application key: <tt class="longboi"
    >de2f4c7672723a692319873e5c227606691a32d1c59d8b9f51dbb9352e9ca9cc</tt>
    <li>client application IV: <tt class="longboi">bb007956f474b25de902432f</tt>
    </ul>
</div>
</div>
</div>

<div class="rec-outer">
<div class="record client">
<div class="rec-label">Client Change Cipher Spec</div>
<div class="rec-explanation">
    This record served a purpose in earlier versions on TLS but is no longer needed.
    In "middlebox compatibility mode" this record is sent to help disguise the session as
    a TLS 1.2 session.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 14 03 03 00 01 01
        </span>
        <div class="explanation">
            TLS sessions are broken into the sending
            and receiving of "records", which are blocks
            of data with a type, a protocol version,
            and a length.
            <ul>
            <li><tt>14</tt> - type is 0x14 (ChangeCipherSpec record)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 01</tt> - the length of the record payload is 1 bytes
            <li><tt>01</tt> - the payload of this message is defined as the byte 0x01
            </ul>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="record client">
<div class="rec-label">Wrapped Record</div>
<div class="rec-explanation">
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, TLS 1.3 records are disguised as TLS 1.2
    application data records.
    <br/><br/>
    The wrapped record is discussed in its own section below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 00 45
        </span>
        <div class="explanation">
            The TLS 1.3 record is encrypted into a TLS
            1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 45</tt> - 0x45 (69) bytes of wrapped data follows
            </ul>
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 9f f9 b0 63 17 51 77 32 2a 46 dd 98 96 f3 c3 bb 82 0a b5 17 43 eb c2 5f da dd 53 45 4b 73 de b5
 4c c7 24 8d 41 1a 18 bc cf 65 7a 96 08 24 e9 a1 93 64 83 7c 35
        </span>
        <div class="explanation">
            This data is encrypted with the client handshake key.
        </div>
    </span>
    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 0a 69 a8 8d 4b f6 35 c8 5e b8 74 ae bc 9d fd e8
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the client
            handshake key and the client handshake IV that were
            generated during the "Client Handshake Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 0.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Client Handshake Keys Calc" step
$ key=1135b4826a9a70257e5a391ad93093dfd7c4214812f493b3e3daae1eb2b1ac69
$ iv=4256d2e0e88babdd05eb2f27
### from this record
$ recdata=1703030045
$ authtag=0a69a88d4bf635c85eb874aebc9dfde8
$ recordnum=0
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "9f f9 b0 63 17 51 77 32 2a 46 dd 98 96 f3 c3 bb 82 0a b5
  17 43 eb c2 5f da dd 53 45 4b 73 de b5 4c c7 24 8d 41 1a 18 bc
  cf 65 7a 96 08 24 e9 a1 93 64 83 7c 35" | xxd -r -p > /tmp/msg2
$ cat /tmp/msg2 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  14 00 00 30 bf f5 6a 67  1b 6c 65 9d 0a 7c 5d d1  |...0..jg.le..|].|
00000010  84 28 f5 8b dd 38 b1 84  a3 ce 34 2d 9f de 95 cb  |.(...8....4-....|
00000020  d5 05 6f 7d a7 91 8e e3  20 ea b7 a9 3a bd 8f 1c  |..o}.... ...:...|
00000030  02 45 4d 27 16                                    |.EM'.|
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Client Handshake Finished</span>
        <span class="bytes">
 14 00 00 30 bf f5 6a 67 1b 6c 65 9d 0a 7c 5d d1 84 28 f5 8b dd 38 b1 84 a3 ce 34 2d 9f de 95 cb
 d5 05 6f 7d a7 91 8e e3 20 ea b7 a9 3a bd 8f 1c 02 45 4d 27
        </span>
        <div class="explanation">
            This handshake message is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 16
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final non-zero byte
            which indicates its actual record type.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake record)
            </ul>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="record client embedded">
<div class="rec-label">Client Handshake Finished</div>
<div class="rec-explanation">
    To verify that the handshake was successful and not tampered
    with, the client calculates verification data that the
    server will agree on, and encrypts it with the client
    handshake key.  The verification data is built from a hash
    of all handshake messages.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 14 00 00 30
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>14</tt> - handshake message type 0x14 (finished)
            <li><tt>00 00 30</tt> - 0x30 (48) bytes of handshake finished data follow
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Verify Data</span>
        <span class="bytes">
 bf f5 6a 67 1b 6c 65 9d 0a 7c 5d d1 84 28 f5 8b dd 38 b1 84 a3 ce 34 2d 9f de 95 cb d5 05 6f 7d
 a7 91 8e e3 20 ea b7 a9 3a bd 8f 1c 02 45 4d 27
        </span>
        <div class="explanation">
            The verify_data is built using the
            client_secret from
            the "Server Handshake Keys Calc" step and
            a SHA384 hash of every handshake record
            before this point (Client Hello to Server Finished).

            <processblock class="notrunc">
<pre>finished_key = HKDF-Expand-Label(key: client_secret, label: "finished", ctx: "", len: 48)
finished_hash = SHA384(Client Hello ... Server Finished)
verify_data = HMAC-SHA384(key: finished_key, msg: finished_hash)
</pre>
            </processblock>

            We can use <a href="files/hkdf-384.sh" download="hkdf-384">the HKDF
            tool</a> to reproduce this on the command line.
            <codesample>
<pre><code>### find the hash of the conversation to this point, excluding
### 5-byte record headers or 1-byte wrapped record trailers
$ fin_hash=$((
    tail -c +6 clienthello;
    tail -c +6 serverhello;
    perl -pe 's/.$// if eof' serverextensions;
    perl -pe 's/.$// if eof' servercert;
    perl -pe 's/.$// if eof' servercertverify;
    perl -pe 's/.$// if eof' serverfinished) | openssl sha384)
$ cht_secret=db89d2d6df0e84fed74a2288f8fd4d0959f790ff23946cdf4c26d85e51bebd42ae184501972f8d30c4a3e4a3693d0ef0
$ fin_key=$(./hkdf-384 expandlabel $cht_secret "finished" "" 48)
$ echo $fin_hash | xxd -r -p \
    | openssl dgst -sha384 -mac HMAC -macopt hexkey:$fin_key

bff56a671b6c659d0a7c5dd18428f58bdd38b184a3ce342d9fde95cbd5056f7da7918ee320eab7a93abd8f1c02454d27
</code></pre>
            </codesample>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="record client">
<div class="rec-label">Wrapped Record</div>
<div class="rec-explanation">
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, TLS 1.3 records are disguised as TLS 1.2
    application data records.
    <br/><br/>
    The wrapped record is discussed in its own section below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 00 15
        </span>
        <div class="explanation">
            The TLS 1.3 record is encrypted into a TLS
            1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 15</tt> - the length of the record payload is 0x15 (21) bytes
            </ul>
            All data following this header is the encrypted form of the actual record.
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 82 81 39 cb 7b
        </span>
        <div class="explanation">
            This data is encrypted with the client application key.
            <br/><br/>
            See below for the decrypted data.
        </div>
    </span>

    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 73 aa ab f5 b8 2f bf 9a 29 61 bc de 10 03 8a 32
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the client
            application key and the client application IV that were
            generated during the "Client Application Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 0.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Client Application Keys Calc" step
$ key=de2f4c7672723a692319873e5c227606691a32d1c59d8b9f51dbb9352e9ca9cc
$ iv=bb007956f474b25de902432f
### from this record
$ recdata=1703030015
$ authtag=73aaabf5b82fbf9a2961bcde10038a32
$ recordnum=0
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "82 81 39 cb 7b" | xxd -r -p > /tmp/msg3
$ cat /tmp/msg3 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  70 69 6e 67 17                                    |ping.|
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Client Application Data</span>
        <span class="bytes">
 70 69 6e 67
        </span>
        <div class="explanation">
            This application data is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 17
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final byte
            which indicates its actual record type.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            </ul>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="record client embedded">
<div class="rec-label">Client Application Data</div>
<div class="rec-explanation">
    The client sends the data "ping".
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Application Data</span>
        <span class="bytes">
 70 69 6e 67
        </span>
        <div class="explanation">
            The bytes "ping".
        </div>
    </span>
</span>
</div>
</div>


<div class="rec-outer">
<div class="record server">
<div class="rec-label">Wrapped Record</div>
<div class="rec-explanation">
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, TLS 1.3 records are disguised as TLS 1.2
    application data records.
    <br/><br/>
    The wrapped records are discussed in their own sections below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 00 ea
        </span>
        <div class="explanation">
            The TLS 1.3 record is encrypted into a TLS
            1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 ea</tt> - the length of the record payload is 0xEA (234) bytes
            </ul>
            All data following this header is the encrypted form of the actual record.
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 38 2d 8c 19 a4 7f 4e 8d 9b 0c 51 0b c3 48 db 2c c9 9b 24 1c d0 d1 8b 31 d0 ca 1a c1 2d c1 e3 03
 c5 8d 0c 7e 9e 27 29 4c 6b 0e 31 98 f7 d3 19 eb 14 62 2e c4 8b 6a c8 f8 66 d7 49 4f a7 75 c8 80
 ff 43 ad 4b 1a f5 3a 03 ca 19 77 95 77 8f ff 2f fe 1d 3b 99 b3 4d e7 82 a7 6a bf a8 40 e6 36 6c
 d7 34 9d 9b cf f6 41 f5 e0 df f9 5e 40 d7 2e 09 ef fe 18 ee 64 67 2c b9 60 05 40 44 88 ad 18 96
 c4 4a 5f d1 74 99 8e 9b 00 94 d8 e6 d8 4d 29 29 b7 88 3d c9 a3 c3 c7 31 3a 87 29 3f 31 b6 1d 24
 d9 90 97 c8 85 3b fb eb 95 d1 d0 1f 99 ca 05 b0 50 18 59 cf 63 40 e8 37 70 75 97 01 52 fa 94 f5
 f5 be 29 06 e7 2a 15 e4 08 36 a4 1f 4c d3 db e7 d5 13 c1 6e 88 61 1d 3e ae 93
        </span>
        <div class="explanation">
            This data is encrypted with the server application key.
            <br/><br/>
            See below for the decrypted data.
        </div>
    </span>

    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 38 d9 db 1f 91 ca 3d 58 42 60 2a 61 0b 43 a4 63
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the server
            application key and the server application IV that were
            generated during the "Server Application Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 0.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Server Application Keys Calc" step
$ key=01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
$ iv=196a750b0c5049c0cc51a541
### from this record
$ recdata=17030300ea
$ authtag=38d9db1f91ca3d5842602a610b43a463
$ recordnum=0
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "38 2d 8c 19 a4 7f 4e 8d 9b 0c 51 0b c3 48 db 2c c9 9b 24
  ... snip ...
  13 c1 6e 88 61 1d 3e ae 93" | xxd -r -p > /tmp/msg5
$ cat /tmp/msg5 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  04 00 00 d5 00 00 1c 20  00 00 00 00 08 00 00 00  |....... ........|
00000010  00 00 00 00 00 00 c0 41  42 43 44 45 46 47 48 49  |.......ABCDEFGHI|
... snip ...
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Server New Session Ticket 1</span>
        <span class="bytes">
 04 00 00 d5 00 00 1c 20 00 00 00 00 08 00 00 00 00 00 00 00 00 00 c0 41 42 43 44 45 46 47 48 49
 4a 4b 4c 4d 4e 4f 00 49 56 44 41 54 41 49 56 44 41 54 41 00 41 45 53 cb 11 9d 4d bd 2a 21 ec c2
 26 a6 09 0e e8 ca 58 df 09 03 9b 35 96 f4 de 79 98 0e a3 25 d5 14 62 5c 0c 21 c5 0f 03 26 1d c4
 2c e7 c5 97 0c 4c 01 ea 33 1c ff c8 99 66 ef 54 8b e4 df 9a 8b a4 38 5b eb 86 80 fd 0b 78 df b8
 e9 8e fc 8f cc d8 14 fe cd 1d 9b ce 89 ca 05 dc 28 c2 49 e5 bd 61 d0 3a 56 8f 9a 0a 46 fb fd 05
 30 2d b6 b2 f7 a3 13 e3 32 67 bf 0b cb dc ec fb 04 a4 d8 2f 5a 69 45 1f 56 7a b5 19 9b b2 6c 5c
 f2 00 72 f0 45 03 73 02 8f e0 71 d4 f4 1d 8f 61 ae 02 4d 69 bb ae 4c 00 00
        </span>
        <div class="explanation">
            This handshake message is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 16
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final byte
            which indicates its actual record type.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake data)
            </ul>
        </div>
    </span>
</span>
</div>
</div>


<div class="rec-outer">
<div class="record server embedded">
<div class="rec-label">Server New Session Ticket 1</div>
<div class="rec-explanation">
    The server provides a session ticket that the client can
    use to start a new session later.  Successfully resuming a
    connection in this way will skip most of the computation
    and network delay in session startup.
    <br/><br/>
    Because each session ticket is meant to be single-use, and
    because the server expects a browser to open multiple
    connections, it makes a size vs. speed decision to provide
    the client with two session tickets for each negotiated
    session.  This is the first ticket.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 04 00 00 d5
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>04</tt> - handshake message type 0x04 (new session ticket)
            <li><tt>00 00 d5</tt> - 0xD5 (213) bytes of session ticket data follow
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Ticket Lifetime</span>
        <span class="bytes">
 00 00 1c 20
        </span>
        <div class="explanation">
            The ticket lifetime of 0x1C20 (7200) seconds, or 2 hours.
        </div>
    </span>

    <span class="string">
        <span class="label">Ticket Age Add</span>
        <span class="bytes">
 00 00 00 00
        </span>
        <div class="explanation">
            When sending this ticket back to the server,
            it must add this number of milliseconds to
            the timestamp indicating when the ticket
            was generated.  This prevents attackers
            from correlating the resumed session with
            the session that generated this ticket.
        </div>
    </span>

    <span class="string">
        <span class="label">Ticket Nonce</span>
        <span class="bytes">
 08 00 00 00 00 00 00 00 00
        </span>
        <div class="explanation">
            A per-ticket value that is unique to each
            ticket generated during this session.
            <ul>
            <li><tt>08</tt> - 8 bytes of nonce data follows
            <li><tt>00 00 00 00 00 00 00</tt> - nonce value
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Session Ticket</span>
        <span class="bytes">
 00 c0 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 00 49 56 44 41 54 41 49 56 44 41 54 41 00 41
 45 53 cb 11 9d 4d bd 2a 21 ec c2 26 a6 09 0e e8 ca 58 df 09 03 9b 35 96 f4 de 79 98 0e a3 25 d5
 14 62 5c 0c 21 c5 0f 03 26 1d c4 2c e7 c5 97 0c 4c 01 ea 33 1c ff c8 99 66 ef 54 8b e4 df 9a 8b
 a4 38 5b eb 86 80 fd 0b 78 df b8 e9 8e fc 8f cc d8 14 fe cd 1d 9b ce 89 ca 05 dc 28 c2 49 e5 bd
 61 d0 3a 56 8f 9a 0a 46 fb fd 05 30 2d b6 b2 f7 a3 13 e3 32 67 bf 0b cb dc ec fb 04 a4 d8 2f 5a
 69 45 1f 56 7a b5 19 9b b2 6c 5c f2 00 72 f0 45 03 73 02 8f e0 71 d4 f4 1d 8f 61 ae 02 4d 69 bb
 ae 4c
        </span>
        <div class="explanation">
            This is the ticket that can be sent to the
            server to resume a session.  The data inside
            is meaningful to the server, and
            may contain enough information for the
            server to safely resume the connection
            without storing any information on the
            server (such as in memory).  This information
            is not meaningful or understandable to the
            client.

            <ul>
            <li><tt>00 c0</tt> - 0xC0 (192) bytes of ticket data follows
            <li><tt>41 42 ... ae 4c</tt> - session ticket
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Ticket Extensions</span>
        <span class="bytes">
 00 00
        </span>
        <div class="explanation">
            The server provides extensions to provide
            more information about the ticket or to
            request a behavioral change from the client.
            <br/><br/>
            <ul>
            <li><tt>00 00</tt> - 0 bytes of "Ticket Extensions" extension data follows
            </ul>
        </div>
    </span>
</span>
</div>
</div>


<div class="rec-outer">
<div class="record server">
<div class="rec-label">Wrapped Record</div>
<div class="rec-explanation">
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, TLS 1.3 records are disguised as TLS 1.2
    application data records.
    <br/><br/>
    The wrapped records are discussed in their own sections below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 00 ea
        </span>
        <div class="explanation">
            The TLS 1.3 record is encrypted into a TLS
            1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 ea</tt> - the length of the record payload is 0xEA (234) bytes
            </ul>
            All data following this header is the encrypted form of the actual record.
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 38 ad fb 1d 01 fd 95 a6 03 85 e8 bb f1 fd 8d cb 46 70 98 97 e7 d6 74 c2 f7 37 0e c1 1d 8e 33 eb
 4f 4f e7 f5 4b f4 dc 0b 92 fa e7 42 1c 33 c6 45 3c eb c0 73 15 96 10 a0 97 40 ab 2d 05 6f 8d 51
 cf a2 62 00 7d 40 12 36 da fc 2f 72 92 ff 0c c8 86 a4 ef 38 9f 2c ed 12 26 c6 b4 dc f6 9d 99 4f
 f9 14 8e f9 69 bc 77 d9 43 3a b1 d3 a9 32 54 21 82 82 9f 88 9a d9 5f 04 c7 52 f9 4a ce 57 14 6a
 5d 84 b0 42 bf b3 48 5a 64 e7 e9 57 b0 89 80 cd 08 ba f9 69 8b 89 29 98 6d 11 74 d4 aa 6d d7 a7
 e8 c0 86 05 2c 3c 76 d8 19 34 bd f5 9b 96 6e 39 20 31 f3 47 1a de bd dd db e8 4f cf 1f f4 08 84
 6a e9 b2 8c a4 a9 e7 28 84 4a 49 3d 80 45 5d 6e af f2 05 b4 0a 1e f1 85 74 ef
        </span>
        <div class="explanation">
            This data is encrypted with the server application key.
            <br/><br/>
            See below for the decrypted data.
        </div>
    </span>

    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 c0 b9 6a d3 83 af bd 8d fc 86 f8 08 7c 1f 7d c8
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the server
            application key and the server application IV that were
            generated during the "Server Application Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 1.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Server Application Keys Calc" step
$ key=01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
$ iv=196a750b0c5049c0cc51a541
### from this record
$ recdata=17030300ea
$ authtag=c0b96ad383afbd8dfc86f8087c1f7dc8
$ recordnum=1
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "38 ad fb 1d 01 fd 95 a6 03 85 e8 bb f1 fd 8d cb 46 70
  ... snip ...
  b4 0a 1e f1 85 74 ef" | xxd -r -p > /tmp/msg5
$ cat /tmp/msg5 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  04 00 00 d5 00 00 1c 20  00 00 00 00 08 00 00 00  |....... ........|
00000010  00 00 00 00 01 00 c0 41  42 43 44 45 46 47 48 49  |.......ABCDEFGHI|
... snip ...
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Server New Session Ticket 2</span>
        <span class="bytes">
 04 00 00 d5 00 00 1c 20 00 00 00 00 08 00 00 00 00 00 00 00 01 00 c0 41 42 43 44 45 46 47 48 49
 4a 4b 4c 4d 4e 4f 00 49 56 44 41 54 41 49 56 44 41 54 41 00 41 45 53 cb 11 9d 4d bd 2a 21 ec c2
 26 a6 09 0e e8 ca 58 df 09 03 9b 35 96 f4 de 79 98 0e a3 25 d5 14 62 5c 0c 21 c5 0f 03 26 1d c4
 2c e7 c5 97 0c 4c 01 16 06 fb 99 8a 86 c3 fa 30 e5 5e ea 91 f1 ff f3 18 fc 7b d5 88 31 bf 49 c8
 8d 7b 59 05 91 a6 5c 7d e8 cf c6 77 46 8a 54 fd be c0 d8 53 be 20 21 c8 bb fc db e5 1f 5d 9a 0c
 70 85 84 1a 01 e4 95 85 f6 8b 4a fe e1 d7 07 e2 cb b1 a0 b4 23 aa 7e 32 d5 60 7b d9 9d d4 db 3c
 9a aa ed 43 d3 5d 26 b4 b1 c6 84 71 71 ea a0 7a 9b c8 cb f7 58 49 9a 00 00
        </span>
        <div class="explanation">
            This handshake message is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 16
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final byte
            which indicates its actual record type.
            <ul>
            <li><tt>16</tt> - type is 0x16 (handshake data)
            </ul>
        </div>
    </span>
</span>
</div>
</div>


<div class="rec-outer">
<div class="record server embedded">
<div class="rec-label">Server New Session Ticket 2</div>
<div class="rec-explanation">
    The server provides a session ticket that the client can
    use to start a new session later.  Successfully resuming a
    connection in this way will skip most of the computation
    and network delay in session startup.
    <br/><br/>
    Because each session ticket is meant to be single-use, and
    because the server expects a browser to open multiple
    connections, it makes a size vs. speed decision to provide
    the client with two session tickets for each negotiated
    session.  This is the second ticket.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Handshake Header</span>
        <span class="bytes">
 04 00 00 d5
        </span>
        <div class="explanation">
            Each handshake message starts with a type and a length.
            <ul>
            <li><tt>04</tt> - handshake message type 0x04 (new session ticket)
            <li><tt>00 00 d5</tt> - 0xD5 (213) bytes of session ticket data follow
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Ticket Lifetime</span>
        <span class="bytes">
 00 00 1c 20
        </span>
        <div class="explanation">
            The ticket lifetime of 0x1C20 (7200) seconds, or 2 hours.
        </div>
    </span>

    <span class="string">
        <span class="label">Ticket Age Add</span>
        <span class="bytes">
 00 00 00 00
        </span>
        <div class="explanation">
            When sending this ticket back to the server,
            it must add this number of milliseconds to
            the timestamp indicating when the ticket
            was generated.  This prevents attackers
            from correlating the resumed session with
            the session that generated this ticket.
        </div>
    </span>

    <span class="string">
        <span class="label">Ticket Nonce</span>
        <span class="bytes">
 08 00 00 00 00 00 00 00 01
        </span>
        <div class="explanation">
            A per-ticket value that is unique to each
            ticket generated during this session.
            <ul>
            <li><tt>08</tt> - 8 bytes of nonce data follows
            <li><tt>00 00 00 00 00 00 01</tt> - nonce value
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Session Ticket</span>
        <span class="bytes">
 00 c0 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 00 49 56 44 41 54 41 49 56 44 41 54 41 00 41
 45 53 cb 11 9d 4d bd 2a 21 ec c2 26 a6 09 0e e8 ca 58 df 09 03 9b 35 96 f4 de 79 98 0e a3 25 d5
 14 62 5c 0c 21 c5 0f 03 26 1d c4 2c e7 c5 97 0c 4c 01 16 06 fb 99 8a 86 c3 fa 30 e5 5e ea 91 f1
 ff f3 18 fc 7b d5 88 31 bf 49 c8 8d 7b 59 05 91 a6 5c 7d e8 cf c6 77 46 8a 54 fd be c0 d8 53 be
 20 21 c8 bb fc db e5 1f 5d 9a 0c 70 85 84 1a 01 e4 95 85 f6 8b 4a fe e1 d7 07 e2 cb b1 a0 b4 23
 aa 7e 32 d5 60 7b d9 9d d4 db 3c 9a aa ed 43 d3 5d 26 b4 b1 c6 84 71 71 ea a0 7a 9b c8 cb f7 58
 49 9a
        </span>
        <div class="explanation">
            This is the ticket that can be sent to the
            server to resume a session.  The data inside
            is meaningful to the server, and
            may contain enough information for the
            server to safely resume the connection
            without storing any information on the
            server (such as in memory).  This information
            is not meaningful or understandable to the
            client.

            <ul>
            <li><tt>00 c0</tt> - 0xC0 (192) bytes of ticket data follows
            <li><tt>41 42 ... 49 9a</tt> - session ticket
            </ul>
        </div>
    </span>

    <span class="string">
        <span class="label">Ticket Extensions</span>
        <span class="bytes">
 00 00
        </span>
        <div class="explanation">
            The server provides extensions to provide
            more information about the ticket or to
            request a behavioral change from the client.
            <br/><br/>
            <ul>
            <li><tt>00 00</tt> - 0 bytes of "Ticket Extensions" extension data follows
            </ul>
        </div>
    </span>
</span>
</div>
</div>


<div class="rec-outer">
<div class="record server">
<div class="rec-label">Wrapped Record</div>
<div class="rec-explanation">
    To reduce issues with middleboxes that block unrecognized
    TLS protocols, TLS 1.3 records are disguised as TLS 1.2
    application data records.
    <br/><br/>
    The wrapped record is discussed in its own section below this one.
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Record Header</span>
        <span class="bytes">
 17 03 03 00 15
        </span>
        <div class="explanation">
            The TLS 1.3 record is encrypted into a TLS
            1.2 record "wrapper" that looks like
            application data.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            <li><tt>03 03</tt> - legacy protocol version of "3,3" (TLS 1.2)
            <li><tt>00 15</tt> - the length of the record payload is 0x15 (21) bytes
            </ul>
            All data following this header is the encrypted form of the actual record.
        </div>
    </span>

    <span class="string encrypted">
        <span class="label">Encrypted Data</span>
        <span class="bytes">
 0c da 85 f1 44
        </span>
        <div class="explanation">
            This data is encrypted with the server application key.
            <br/><br/>
            See below for the decrypted data.
        </div>
    </span>

    <span class="string">
        <span class="label">Auth Tag</span>
        <span class="bytes">
 7a e2 3f a6 6d 56 f4 c5 40 84 82 b1 b1 d4 c9 98
        </span>
        <div class="explanation">
            This is the AEAD authentication tag
            that protects the integrity of the
            encrypted data and the record header.
        </div>
    </span>

    <div class="decryption">
        <div class="label">Decryption</div>
        <div class="explanation">
            This data is encrypted using the server
            application key and the server application IV that were
            generated during the "Server Application Keys
            Calc" step.  The IV will be modified
            by XOR'ing it by the count of records that
            have already been encrypted with this key,
            which in this case is 2.  The process also
            takes as input the 5-byte record header
            that this record begins with, as authenticated
            data that must match for the decryption to
            succeed.
            <br/><br/>
            Because the <tt>openssl</tt> command line
            tool does not yet support AEAD ciphers,
            I've written command line tools to both
            <a href="files/aes_256_gcm_decrypt.c" download="aes_256_gcm_decrypt.c">decrypt</a>
            and <a href="files/aes_256_gcm_encrypt.c" download="aes_256_gcm_encrypt.c">encrypt</a>
            this data.
            <codesample>
<pre><code>### from the "Server Application Keys Calc" step
$ key=01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
$ iv=196a750b0c5049c0cc51a541
### from this record
$ recdata=1703030015
$ authtag=7ae23fa66d56f4c5408482b1b1d4c998
$ recordnum=2
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "0c da 85 f1 44" | xxd -r -p > /tmp/msg4
$ cat /tmp/msg4 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  70 6f 6e 67 17                                    |pong.|
</code></pre>
            </codesample>
        </div>
    </div>

    <span class="string decrypted">
        <span class="label">Server Application Data</span>
        <span class="bytes">
 70 6f 6e 67
        </span>
        <div class="explanation">
            This application data is represented in its own section below.
        </div>
    </span>

    <span class="string decrypted">
        <span class="label">Record Type</span>
        <span class="bytes">
 17
        </span>
        <div class="explanation">
            Each TLS 1.3 record disguised as TLS 1.2
            application data has a final byte
            which indicates its actual record type.
            <ul>
            <li><tt>17</tt> - type is 0x17 (application data)
            </ul>
        </div>
    </span>
</span>
</div>
</div>

<div class="rec-outer">
<div class="record server embedded">
<div class="rec-label">Server Application Data</div>
<div class="rec-explanation">
    The server replies with the data "pong".
</div>
<span class="record-data">
    <span class="string">
        <span class="label">Application Data</span>
        <span class="bytes">
 70 6f 6e 67
        </span>
        <div class="explanation">
            The bytes "pong".
        </div>
    </span>
</span>
</div>
</div>

    <div class="outerblock">
    <p>The code for this project, including packet captures, can be found
    <a href="https://github.com/syncsynchalt/illustrated-tls13">on GitHub</a>.</p>
    </div>

    <div class="outerblock">
    <p>If you found this page useful or interesting let me know via Twitter
    <a href="https://twitter.com/xargsnotbombs">@XargsNotBombs</a>.</p>
    </div>

</div>

<div id="templates" style="display: none">
    <div id="showCodeTmpl">
        <!--suppress JSDeprecatedSymbols -->
        <button class="show-code" onclick="ill.showCode(this, event)">Show Code</button>
    </div>
    <!--suppress JSDeprecatedSymbols -->
    <button id="annotateTmpl" class="annotate-toggle"
        onclick="ill.toggleAnnotate(this.parentElement, event)">Annotations</button>
</div>

<!--suppress HtmlUnknownAnchorTarget -->
<a class="print-mode" href="#print" onclick="ill.printMode()">
    [print]
</a>
</div>
</body>
</html>
